package com.app.library.base

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelStoreOwner
import androidx.viewbinding.ViewBinding
import com.app.library.R
import com.app.library.ext.viewbinding.base.FragmentBinding
import com.app.library.ext.viewbinding.base.FragmentBindingDelegate
import com.app.library.utils.CustomToast
import com.app.library.utils.ToasterUtils
import com.app.library.utils.ViewModelUtils
import retrofit2.HttpException

abstract class LibFragment<VB : ViewBinding, VM : LibViewModel> : Fragment(), LibView,IFragmentVisibility,
    FragmentBinding<VB> by FragmentBindingDelegate() {

    protected val tagKey: String by lazy { javaClass.simpleName }

    private var loadingDialog: LoadingDialog? = null
    protected lateinit var mViewModel: VM
    protected var isCreateView: Boolean = false

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return createViewWithBinding(inflater, container)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        isCreateView = true
        initBaseModel()
        initData(savedInstanceState)
        initView()
    }

    private fun initBaseModel() {
        mViewModel = ViewModelUtils.getWithGeneric(viewModelOwner())
        activity ?: return
        mViewModel.apply {
            toast.observe(requireActivity()) {
                showToast(it)
            }
            loading.observe(requireActivity()) {
                if (it == null) {
                    dismissLoading()
                } else {
                    showLoading(it)
                }
            }
            exception.observe(requireActivity()) {
                handleError(it)
            }
        }
    }

    private fun handleError(throwable: Throwable) {
        throwable.printStackTrace()
        when (throwable) {
            is ApiException -> {
                handleApiExp(throwable)
            }
            is HttpException -> {
//                showToast(getString(R.string.error_no_network))
            }
            else -> {
//                showToast(getString(R.string.error_no_network))
            }
        }
    }

    abstract fun handleApiExp(exception: ApiException)


    override fun showLoading(msg: String?) {
        if (activity is LibActivity<*, *>) {
            (activity as LibActivity<*, *>).showLoading(msg)
        } else {
            if (loadingDialog == null) {
                loadingDialog = LoadingDialog(activity ?: return)
                loadingDialog?.setCanceledOnTouchOutside(false)
                loadingDialog?.setCancelable(true)
            }
            if (loadingDialog?.isShowing == false)
                loadingDialog?.show(msg)
        }
    }

    override fun dismissLoading() {
        if (activity is LibActivity<*, *>) {
            (activity as LibActivity<*, *>).dismissLoading()
        } else {
            loadingDialog?.dismiss()
        }
    }


    override fun showToast(msg: String?) {
        msg ?: return
        ToasterUtils.showShort(msg)
    }

    override fun showToast(res: Int) {
        showToast(getString(res))
    }

    override fun onDestroyView() {
        RxNetLife.clear(tagKey)
        isCreateView = false
        super.onDestroyView()
    }

    open fun viewModelOwner(): ViewModelStoreOwner {
        return this
    }

    override fun onResume() {
        super.onResume()

        determineFragmentVisible()
    }

    override fun onPause() {
        super.onPause()

        determineFragmentInvisible()
    }

    // Fragment当前是否对用户可见。
    private var mIsFragmentVisible = false
    // Fragment当前是否是第一次对用户可见。
    private var mIsFragmentVisibleFirst = true

    private fun determineFragmentVisible() {
        if (isResumed && !isHidden && userVisibleHint && !mIsFragmentVisible) {
            mIsFragmentVisible = true
            onVisible()
            if (mIsFragmentVisibleFirst) {
                mIsFragmentVisibleFirst = false
                onVisibleFirst()
            } else {
                onVisibleExceptFirst()
            }
        }
    }
    private fun determineFragmentInvisible() {
        if (mIsFragmentVisible) {
            mIsFragmentVisible = false
            onInvisible()
        }
    }
}